/*Test Distrubition Server. Copyright (C) 2007-2008 Cameron de Witte. (cameron.dewitte@gmail.com)
* 
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public 
* License as published by the Free Software Foundation, either version 3 of the License, or any later version. 
* 
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
* 
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public 
* License along with this program. If not, see http://www.gnu.org/licenses/. 
*/


using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.Xml;

namespace TestDistrubitionServer
{
    public partial class frmMain : Form, IMainForm
    {
        private const int SB_BOTTOM = 7;
        private const int WM_VSCROLL = 277;
        private readonly string[] clients;
        private readonly int maxClients = 20;
        private readonly int port;
        private readonly TcpServer server;
        private readonly Thread thread;
        private int numClientsConnected = 0;

        public frmMain()
        {
            try
            {
                XmlDocument XMLDoc = new XmlDocument();
                XMLDoc.Load("config.xml");
                XmlNodeList XMLNodes = XMLDoc.GetElementsByTagName("Config");
                XmlElement elem = (XmlElement) XMLNodes[0];
                port = Convert.ToInt32(elem.GetElementsByTagName("ListenPort")[0].InnerText);
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show("Could not find the config file, using default settings.", "File not found",
                                MessageBoxButtons.OK, MessageBoxIcon.Warning);
                port = 4231;
            }

            clients = new string[maxClients];
            findFreeSlot(true);
            server = new TcpServer(port, this);
            InitializeComponent();

            thread = new Thread(delegate() { server.Run(); });
            thread.Start();
        }

        #region IMainForm Members

        public void AddLine(string line)
        {
            if (tbLog.InvokeRequired)
            {
                tbLog.Invoke(new AddLineDelegate(AddLine), line);
            }
            else
            {
                tbLog.AppendText("\r\n" + line);
                SendMessage(tbLog.Handle, WM_VSCROLL, SB_BOTTOM, 0);
            }
        }

        public int AddClient(string clientName, string clientMachineName)
        {
            if (lblClients.InvokeRequired)
            {
                lblClients.Invoke(new AddClientsDelegate(AddClient), clientName, clientMachineName);
            }
            else
            {
                int clientID = findFreeSlot(false);
                clients[clientID] = clientName;
                ListViewItem item = new ListViewItem(clientID.ToString());
                item.SubItems.Add(clientName);
                item.SubItems.Add(clientMachineName);
                lvClients.Items.Add(item);
                numClientsConnected++;
                lblClients.Text = "Connected Clients: " + numClientsConnected;
                return clientID;
            }
            return -1;
        }

        public int RemoveClient(int clientID)
        {
            if (lblClients.InvokeRequired)
            {
                lblClients.Invoke(new RemoveClientsDelegate(RemoveClient), clientID);
            }
            else
            {
                numClientsConnected--;
                lblClients.Text = "Connected Clients: " + numClientsConnected;
            }
            return -1;
        }

        #endregion

        private int findFreeSlot(bool init)
        {
            if (init)
            {
                for (int i = 0; i < maxClients; i++)
                {
                    clients[i] = "-1";
                }
                return -1;
            }
            else
            {
                for (int i = 0; i < maxClients; i++)
                {
                    if (clients[i] == "-1")
                    {
                        return i;
                    }
                }
                return -1;
            }
        }

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr handle, int message, int wparam, int lparam);

        protected override void OnClosing(CancelEventArgs e)
        {
            server.Stop();
            thread.Abort();

            base.OnClosing(e);
        }

        private void frmMain_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == WindowState)
            {
                niTrayIcon.Icon = Icon;
                niTrayIcon.Visible = true;
                niTrayIcon.BalloonTipTitle = "Test Distrubition Server";
                niTrayIcon.BalloonTipText =
                    "Test Distrubition Server has been placed in the tray.\r\nDouble click to show window.";
                niTrayIcon.ShowBalloonTip(500);
                ShowInTaskbar = false;
            }
            else
            {
                niTrayIcon.Visible = false;
            }
        }

        private void niTrayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            WindowState = FormWindowState.Normal;
            niTrayIcon.Visible = false;
            ShowInTaskbar = true;
            Visible = true;
            Activate();
        }

        #region Tabs

        private void btnInfo_Click(object sender, EventArgs e)
        {
            pnlInfo.Visible = true;
            pnlClients.Visible = false;
        }

        private void btnClients_Click(object sender, EventArgs e)
        {
            pnlClients.Visible = true;
            pnlInfo.Visible = false;
        }

        #endregion

        #region Nested type: AddClientsDelegate

        private delegate int AddClientsDelegate(string clientName, string clientMachineName);

        #endregion

        #region Nested type: AddLineDelegate

        private delegate void AddLineDelegate(string line);

        #endregion

        #region Nested type: RemoveClientsDelegate

        private delegate int RemoveClientsDelegate(int clientID);

        #endregion
    }
}